import screenlets
import wnck
import gobject
import cairo
import os
import gtk
import threading

class ApplicationIconWidget (screenlets.ShapedWidget):
	command = None
	
	# privates
	__icon = None
	__shadow = None
	__windows = None
	__lock = None # prevent async access
	
	__name = None
	
	# No way to activate app on start, so on activate on opening window
	__activate_next_win = False
	
	# attributes/properties
	icon_size = 32		# size of icon to be drawn (not widget size)
	shadow_offset = 3
	shadow_alpha = 0.4
	hover_color = (1, 1, 1)		# hover/flashing color
	hover_alpha = 0.5			# hover/flashing alpha
	
	# for custom signals
	__gsignals__ = dict(
		icon_left_clicked=(gobject.SIGNAL_RUN_FIRST,
			gobject.TYPE_NONE, (gobject.TYPE_OBJECT,
			gobject.TYPE_INT)),
		icon_right_clicked=(gobject.SIGNAL_RUN_FIRST,
			gobject.TYPE_NONE, (gobject.TYPE_OBJECT,
			gobject.TYPE_INT)))
	
	# constructor
	def __init__ (self, width, height, name, command, icon):
		# call super
		super(ApplicationIconWidget, self).__init__(width, height)
		
		self.command = command
		self.__name = name
		
		self.__icon = icon
		self.__shadow = self.__icon.copy()
		self.__icon.saturate_and_pixelate(self.__shadow, 0.0, False)
			
		self.queue_draw()
		
		# set size of widget
		self.set_size_request(width, height)
		
		self.__windows = []
		self.__lock = threading.Lock()
		
	def get_name(self):
		return self.__name
		
	def open_window(self, wnckwin):
		self.__windows.append(wnckwin)
		self.queue_draw()
		
		if self.__activate_next_win:
			wnckwin.activate(gtk.get_current_event_time())
			
		self.__activate_next_win = False
	
	def close_window(self,wnckwin):
		self.__windows.remove(wnckwin)
		self.queue_draw()
		
	def related_to(self,wnckwin):
		for win in self.__windows:
			if win == wnckwin:
				return True
		
		# it may be new window - lookup by app name
		if wnckwin.get_application() == None:
			return None
		
		name = wnckwin.get_application().get_name()
		return name == self.__name

	
	# handle button-press on this ApplicationIconWidget
	# if application is started - switch to it. Otherwise create new instance
	def button_press (self, widget, e):
		if e.button != 1: return # left button only
		
		with self.__lock:
			if len(self.__windows) == 0 or e.type == gtk.gdk._2BUTTON_PRESS:
				if not self.__activate_next_win:
					os.system(self.command + "&")
					self.__activate_next_win = True
			else: 
				if len(self.__windows) == 1: # if only one window and it is active - just hide it
					active_window = wnck.screen_get_default().get_active_window()
					
					if self.__windows[0] == active_window:
						active_window.minimize()
						return
					
				next_win = self.__get_next_win()
				next_win.activate(gtk.get_current_event_time())
			
 	def __get_next_win(self):
 		if len(self.__windows) == 0: return None
 		
 		win = self.__windows[0]
 		
 		# rotate windows array, to cycle thru windows on single click
 		for i in range(len(self.__windows) - 1):
 			self.__windows[i] = self.__windows[i + 1]
 			
 		self.__windows[len(self.__windows) - 1] = win 
 		
 		return win
	
	# draw highlight/flashing effect over a hovered item
	def draw_highlight (self, ctx):
		ctx.save()
		ctx.rectangle(0, 0, 
			self.icon_size + self.shadow_offset, 
			self.icon_size + self.shadow_offset)
		ctx.set_operator(cairo.OPERATOR_ATOP)
		c = self.hover_color
		ctx.set_source_rgba(c[0], c[1], c[2], 
			self.hover_alpha)
		ctx.fill()
		ctx.restore()
	
	# drawing-handler: draw icon
	def draw (self, ctx):
		ctx.set_operator(cairo.OPERATOR_OVER)
		
		# draw shadow
		self.window.draw_pixbuf(None, self.__icon, 0, 0, self.shadow_offset, self.shadow_offset)
		
		ctx.save()
		ctx.translate(self.shadow_offset, self.shadow_offset)
		ctx.set_operator(cairo.OPERATOR_IN)
		ctx.rectangle(0, 0, self.icon_size, self.icon_size)
		ctx.clip_preserve()
		ctx.set_source_rgba(0, 0, 0, self.shadow_alpha)
		ctx.fill()
		ctx.restore()
		
		# active?
		if len(self.__windows) > 0:
			self.window.draw_pixbuf(None, self.__icon, 0, 0, 0, 0)
		else:
			self.window.draw_pixbuf(None, self.__shadow, 0, 0, 0, 0)
			
		# lighten when hovered (or flashing)
		if self.mouse_inside:
			self.draw_highlight(ctx)			